import logging
from flask import g, redirect, render_template, request, jsonify, session, current_app, abort
from flask_session import Session

from info import db, redis_store
from info.modules import constants
from info.modules.models import User, News, tb_user_collection, Category
from info.utils.image_storage import storage
from info.utils.response_code import RET
from . import profile_blue
from info.utils.common import set_func


# 我们在这里开始写路由函数
@profile_blue.route('/info')
@set_func
def user_info():

    user = g.user
    # 这里是整个个人中心的父页面,在这里判断用户有没有登录,别的子页面就不用判断了,
    # 如果用户未登录,我们就让他滚回主页
    if not user:
        return redirect('/')

    data = {
        'user': user.to_dict()
    }

    return render_template('news/user.html', data=data)


# 这里写用户修改个人资料
@profile_blue.route('/base_info', methods=['GET', 'POST'])
@set_func
def get_user_info():
    # GET是用来获取页面的,用get方式来渲染模板
    user = g.user
    data = {
        'user': user.to_dict()
    }
    if request.method == 'GET':
        # 将目前已经选择好的nick_name和其他的之类的返回
        return render_template('news/user_base_info.html', data=data)

    # 获取参数
    nick_name = request.json.get('nick_name')
    signature = request.json.get('signature')
    gender = request.json.get('gender')

    # 校验参数
    if not all([nick_name, gender]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不对')
    # 判断性别在不在选项之中
    if gender not in ['MAN', 'WOMEN']:
        return jsonify(errno=RET.PARAMERR, errmsg='参数不正确')

    # 逻辑处理,就直接将数据保存到数据库去
    user.nick_name = nick_name
    user.signature = signature
    user.gender = gender

    try:
        db.session.commit()
    except Exception as e:
        # 用日志记录
        logging.error(e)
        # 数据提交失败要记得回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='数据库错误')

    # 与此同时,我们要将redis中的数据更新,
    session['nick_name'] = nick_name
    return jsonify(errno=RET.OK, errmsg='ok')


# 这里是更新用户头像的地方
@profile_blue.route('/pic_info', methods=['GET', 'POST'])
@set_func
def get_avatar_url():
    # 首先读取已经有的头像图片
    user = g.user
    if request.method == 'GET':
        data = {
            'user': user.to_dict()
        }
        return render_template('news/user_pic_info.html', data=data)

    # 获取参数,我们是从前端获得用户上传的图片文件
    try:
        avatar_data = request.files.get('avatar').read()
    except Exception as e:
        # 用日志记录
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据错误')

    # 逻辑处理,上传七牛云
    # 上传需要捕获错误.
    try:
        avatar_name = storage(avatar_data)
    except Exception as e:
        # 用日志记录
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='上传失败')

    # 取到图片之后,我们就将图片的地址加到数据库里面去
    user.avatar_url = avatar_name

    try:
        db.session.commit()
    except Exception as e:
        # 用日志记录
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='更新图片错误')
    return jsonify(errno=RET.OK, errmsg='ok', data={'avatar_url': constants.QINIU_DOMIN_PREFIX + avatar_name})


@profile_blue.route('/pass_info', methods=['GET', 'POST'])
@set_func
def change_password():
    user = g.user
    if request.method == 'GET':
        data = {
            'user': user.to_dict()
        }
        return render_template('news/user_pass_info.html', data=data)

    # 获取就密码和新密码
    old_password = request.json.get('old_password')
    new_password = request.json.get('new_password')
    new_password2 = request.json.get('new_password')

    # 校验密码
    if not all([old_password, new_password, new_password2]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')

    # 逻辑处理
    # 比较旧密码和数据库里面的密码是否一致
    if not user.check_passowrd(old_password):
        return jsonify(errno=RET.PARAMERR, errmsg='密码错误')

    # 设置新密码
    user.password = new_password

    # 提交数据库
    try:
        db.session.commit()
    except Exception as e:
        # 用日志记录
        logging.error(e)
        # 回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='数据库错误')

    return jsonify(errno=RET.OK, errmsg='OK')


# 定义一个用户收藏的界面
@profile_blue.route('/collection')
@set_func
def user_collection():
    # 获取页码
    page = request.args.get('page', 1)
    try:
        page = int(page)
    except Exception as e:
        current_app.logger.error(e)
        # 如果页码不是int类型的数据, 可能在查询数据库时有问题
        page = 1

    # 查询数据库
    user = g.user
    collection_models = None
    current_page = 1
    total_page = 1

    # 这里直接逻辑处理
    try:
        paginate = user.collection_news.paginate(page, constants.USER_COLLECTION_MAX_NEWS, False)
        collection_models = paginate.items
        current_page = paginate.page
        total_page = paginate.pages
    except Exception as e:
        # 用日志记录
        logging.error(e)
        # return jsonify(errno=RET.DBERR, errmsg='cuowu')

    # 遍历得到的字典
    collected_news = []
    for collect in collection_models:
        collected_news.append(collect.to_dict())

    data = {
        'collection_list': collected_news,
        'current_page': current_page,
        'total_page': total_page
    }
    return render_template('news/user_collection.html', data=data)


# 在这里我们开始写 新闻发布的页面
'''
    新闻发布,首先先检查用户是否登录,
    先判断是否是GET,返回渲染界面,把user里面的地址改一下,
    然后在点击提交的时候我们要,使用post的方式上传数据,也就是创建模型,提交数据库
    我们可以用request,form进行获取表单中的数据
    
'''


@profile_blue.route('/news_release', methods=['GET', 'POST'])
@set_func
def commit_news():
    # 首先判断用户是否存在
    user = g.user
    if request.method == 'GET':

        category = []
        if user:
            try:
                category = Category.query.all()
            except Exception as e:
                # 用日志记录
                logging.error(e)
                return jsonify(errno=RET.DBERR, errmsg='数据库错误')

            # 转成列表
            categories_list = []
            for categories in category:
                categories_list.append(categories.to_dict())
            categories_list.pop(0)
            data = {
                'category_list': categories_list
            }
            return render_template('news/user_news_release.html', data=data)

    # 如果是post请求,我们就获取表单数据
    title = request.form.get('title')
    category_id = request.form.get('category_id')
    digest = request.form.get('digest')
    content = request.form.get('content')
    image = request.files.get('index_image')
    source = '雷晶晶'

    # 校验参数
    if not all([title, category_id, digest, content]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不全')

    # 这里也可以校验一下,对于标题是否过长,摘要是否过长的检测.
    # 我们在这块对于category_id进行检测
    try:
        category_id = int(category_id)
    except Exception as e:
        # 用日志记录
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='错误')

    try:
        category_models = Category.query.get(category_id)
    except Exception as e:
        # 用日志记录
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='错误')

    if not category_models:
        return jsonify(errno=RET.DBERR, errmsg='无分类数据')

    news = News()
    # 如果存在图片,我们要提交到七牛云
    if image:
        image_data = image.read()

        # 调用七牛云进行上传,需要捕获错误
        try:
            image_url = storage(image_data)
            news.index_image_url = constants.QINIU_DOMIN_PREFIX + image_url
        except Exception as e:
            logging.error(e)
            return jsonify(errno=RET.THIRDERR, errmsg='上传失败')

    # 如果都通过,我们就可以创建模型将数据提交到数据库了
    news.title = title
    news.category_id = category_id
    news.digest = digest
    news.content = content
    news.user_id = user.id
    news.status = 1
    news.source = source

    try:
        db.session.add(news)
        db.session.commit()
    except Exception as e:
        # 用日志记录
        logging.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='数据库错误')

    return jsonify(errno=RET.OK, errmsg='ok')


# 这里写新闻列表的部分
'''
    新闻已发布列表就是通过用户的id查到用户所发布的新闻,进行分页显示
'''


@profile_blue.route('/news_list')
@set_func
def news_list():
    # 先不多bb,检验用户
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg='用户未登录')

    # 获取页码
    page = request.args.get('page', 1)
    # 对于获取的page进行转换成整型
    try:
        page = int(page)
    except Exception as e:
        # 用日志记录
        logging.error(e)

    # 我们要对一些数据进行初始化操作
    user_news_models = None
    current_page = 1
    total_page = 1
    # 如果用户通过,我们就开始查询用户所发布的新闻
    try:
        paginate = News.query.filter(News.user_id == user.id).paginate(page, constants.ADMIN_NEWS_PAGE_MAX_COUNT, False)
    except Exception as e:
        # 用日志记录
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库错误了')

    # 将分页后的数据取出来
    user_news_models = paginate.items
    current_page = paginate.page
    total_page = paginate.pages

    # 对于获取到的新闻列表进行遍历
    user_news_list = []
    for user_news in user_news_models:
        user_news_list.append(user_news.to_dict())

    data = {
        'news_list': user_news_models,
        'current_page': current_page,
        'total_page': total_page
    }

    return render_template('news/user_news_list.html', data=data)


# 这里写 用户关注的路由
@profile_blue.route('/user_followed')
@set_func
def user_followed():
    # 分页查询
    # 获取页数
    try:
        page = request.args.get('p', 1)
        page = int(page)
    except Exception as e:
        # 用日志记录
        logging.error(e)
        page = 1

    # 创建初始参数
    user = g.user
    followed_models = None
    current_page = 1
    total_page = 1

    # 查询
    try:
        followed = user.followed.paginate(page, constants.USER_FOLLOWED_MAX_COUNT, False)
        followed_models = followed.items
        current_page = followed.page
        total_page = followed.pages
    except Exception as e:
        # 用日志记录
        logging.error(e)
        return jsonify(errno=RET.DBERR, errmsg='出错')

    follow_list = []
    # 遍历用户
    for follow in followed_models if followed_models else []:
        follow_list.append(follow.to_dict())

    data = {
        'users': follow_list,
        'total_page': total_page,
        'current_page': current_page
    }

    return render_template('news/user_follow.html', data=data)


# 这里是其他用户的模块
# 就是点击关注的名片模块,跳转到用户的详情模块
@profile_blue.route('/other_info')
@set_func
def other_info():
    # 我们需要获取用户的id,
    user = g.user

    if not user:
        return jsonify(errno=RET.PARAMERR, errmsg='用户出错')

    # 获取关注着的id
    followed_id = request.args.get('user_id')

    if not followed_id:
        abort(404)

    followed = None
    try:
        followed = User.query.get(followed_id)
    except Exception as e:
        # 用日志记录
        logging.error(e)

    if not followed:
        abort(404)

    is_followed = False

    if user and followed:
        if followed in user.followed:
            is_followed = True

    data = {
        "is_followed": is_followed,
        "user": g.user.to_dict() if g.user else None,
        "other_info": followed.to_dict()
    }
    return render_template('news/other.html', data=data)


@profile_blue.route('/other_news_list')
@set_func
def other_news_list():
    # 获取参数
    followed_id = request.args.get('user_id')
    page = request.args.get('p', 1)

    # 校验页数
    try:
        page = int(page)
    except Exception as e:
        # 用日志记录
        logging.error(e)

    # 查询作者
    try:
        followed = User.query.get(followed_id)
    except Exception as e:
        # 用日志记录
        logging.error(e)

    # 初始化数据
    user = g.user
    news_models = None
    current_page = 1
    total_page = 1

    # 进行分页查询
    try:
        paginate = News.query.filter(News.user_id == followed_id).paginate(page, constants.ADMIN_NEWS_PAGE_MAX_COUNT, False)
        news_models = paginate.items
        current_page = paginate.page
        total_page = paginate.pages
    except Exception as e:
        # 用日志记录
        logging.error(e)

    # 遍历新闻列表
    news_lists = []
    for news in news_models:
        news_lists.append(news.to_review_dict())

    # 返回数据
    data = {
        "news_list": news_lists,
        "total_page": total_page,
        "current_page": current_page
    }

    return jsonify(errno=RET.OK, errmsg='OK', data=data)





